

var Camera = (function(){

	//var view_matrix_;
	
	function Camera(init_pos, init_rot){
		var view_matrix_ = mat4.create();
		var projection_matrix_ = mat4.create();
		
		var world_position_ = [0.0, 0.0, 0.0];
		
		var initial_pos_ = [0.0, 0.0, 0.0];
		
		var add_tilt_ = [0.0, 0.0, 0.0];
		
		var shadow_step_;
		
		var b_look_at_ = false;
		var center_;
		var target_;
		var up_;
		
		var random_vec = new Float32Array(3);
		
		mat4.identity(view_matrix_);
		
		mat4.rotateZ(view_matrix_, init_rot[2]);
		mat4.rotateX(view_matrix_, init_rot[0]);
		mat4.rotateY(view_matrix_, init_rot[1]);
		
		mat4.translate(view_matrix_, [-init_pos[0], -init_pos[1], -init_pos[2]]);
		
		//view_matrix_[12] = -init_pos[0];
		//view_matrix_[13] = -init_pos[1];
		//view_matrix_[14] = -init_pos[2];
		
		initial_pos_[0] = -init_pos[0];
		initial_pos_[1] = -init_pos[1];
		initial_pos_[2] = -init_pos[2];
		
				
		world_position_[0] = -(view_matrix_[0]*view_matrix_[12] + view_matrix_[1]*view_matrix_[13] + view_matrix_[2]*view_matrix_[14]);
		world_position_[1] = -(view_matrix_[4]*view_matrix_[12] + view_matrix_[5]*view_matrix_[13] + view_matrix_[6]*view_matrix_[14]);
		world_position_[2] = -(view_matrix_[8]*view_matrix_[12] + view_matrix_[9]*view_matrix_[13] + view_matrix_[10]*view_matrix_[14]);
		

		var planes_ = [];
			planes_.left = [0.0, 0.0, 0.0, 0.0];
			planes_.right = [0.0, 0.0, 0.0, 0.0];
			planes_.far = [0.0, 0.0, 0.0, 0.0];
			planes_.near = [0.0, 0.0, 0.0, 0.0];
			planes_.top = [0.0, 0.0, 0.0, 0.0];
			planes_.bottom = [0.0, 0.0, 0.0, 0.0];

		
		this.view_matrix = function(){
			return view_matrix_;
		};
				
		this.projection_matrix = function(){
			return projection_matrix_;
		};
		
		this.view_proj_matrix = function(){
			var view_proj_matrix = mat4.create();
			mat4.multiply(projection_matrix_, view_matrix_, view_proj_matrix);
			return view_proj_matrix;
		};
		
		this.initial_pos = function(){
			return initial_pos_;
		};
		
		this.world_position = function(){
			return world_position_;
		};
		
		this.Perspective = function(angle, aspect, near, far){
			mat4.perspective(angle, aspect, near, far, projection_matrix_);
		};
				
		this.Orthographic = function(left, right, down, up, near, far){
			mat4.ortho(left, right, down, up, near, far, projection_matrix_);
			//shadow_step_ = ( right - left ) / SHADOW_MAP_RES;
		};
		
		this.Translate = function(x, y, z){
			mat4.translate(view_matrix_, [x, y, z]);
		};
		
		this.LookAtMatrix = function(center, target, up){
			mat4.identity(view_matrix_);
			view_matrix_ = mat4.lookAt(center, target, up);
			b_look_at_ = true;
			target_ = target;
			up_ = up;
			center_ = center;
							
			world_position_[0] = -(view_matrix_[0]*view_matrix_[12] + view_matrix_[1]*view_matrix_[13] + view_matrix_[2]*view_matrix_[14]);
			world_position_[1] = -(view_matrix_[4]*view_matrix_[12] + view_matrix_[5]*view_matrix_[13] + view_matrix_[6]*view_matrix_[14]);
			world_position_[2] = -(view_matrix_[8]*view_matrix_[12] + view_matrix_[9]*view_matrix_[13] + view_matrix_[10]*view_matrix_[14]);
		
		};
		
		
		this.Follow = function(parent){
					
			//mat4.identity(view_matrix_);
			/*
			mat4.rotateZ(view_matrix_, init_rot[2]);
			mat4.rotateX(view_matrix_, init_rot[0]);
			mat4.rotateY(view_matrix_, init_rot[1]);*/
			
			//var temp_matr = mat4.create();
			var temp_matr = parent.local_matrix();
			
			if(!b_look_at_){
				mat4.identity(view_matrix_);
			
				mat4.rotateZ(view_matrix_, init_rot[2]);
				mat4.rotateX(view_matrix_, init_rot[0]);
				mat4.rotateY(view_matrix_, init_rot[1]);
			
				mat4.translate(view_matrix_, [-init_pos[0], -init_pos[1], -init_pos[2]]);
			}else{
				view_matrix_ = mat4.lookAt(center_, target_, up_);
			}
			view_matrix_[12] -= (temp_matr[12] * view_matrix_[0] + temp_matr[13] * view_matrix_[4] + temp_matr[14] * view_matrix_[8]);
			view_matrix_[13] -= (temp_matr[12] * view_matrix_[1] + temp_matr[13] * view_matrix_[5] + temp_matr[14] * view_matrix_[9]);
			view_matrix_[14] -= (temp_matr[12] * view_matrix_[2] + temp_matr[13] * view_matrix_[6] + temp_matr[14] * view_matrix_[10]);
			
			world_position_[0] = -(view_matrix_[0]*view_matrix_[12] + view_matrix_[1]*view_matrix_[13] + view_matrix_[2]*view_matrix_[14]);
			world_position_[1] = -(view_matrix_[4]*view_matrix_[12] + view_matrix_[5]*view_matrix_[13] + view_matrix_[6]*view_matrix_[14]);
			world_position_[2] = -(view_matrix_[8]*view_matrix_[12] + view_matrix_[9]*view_matrix_[13] + view_matrix_[10]*view_matrix_[14]);
			
		};
		
		this.CorrectPos4ShadowMap = function(){
			
			view_matrix_[12] = Math.floor( view_matrix_[12] / shadow_step_ ) * shadow_step_;
			view_matrix_[13] = Math.floor( view_matrix_[13] / shadow_step_ ) * shadow_step_;
			view_matrix_[14] = Math.floor( view_matrix_[14] / shadow_step_ ) * shadow_step_;
			
		};
		
		this.TiltRandomly = function(){
			
			
			
			//mat4.translate(view_matrix_, [-add_tilt_[0], 0.0, 0.0]);
			
			if(cur_time - tilt_cam_time > 1000){
			tilt_cam_time = cur_time;
			random_vec[0] = Math.random() * 0.00008 - 0.00004;
			random_vec[1] = Math.random() * 0.00008 - 0.00004;
			random_vec[2] = Math.random() * 0.00008 - 0.00004;
			
			var inv_l = 1/Math.sqrt( random_vec[0]*random_vec[0]+random_vec[1]*random_vec[1]+random_vec[2]*random_vec[2] );
			
			random_vec[0] *= inv_l;
			random_vec[1] *= inv_l;
			random_vec[2] *= inv_l;
			}
			
			add_tilt_[0] += random_vec[0] * 0.01;
			add_tilt_[1] += random_vec[1] * 0.01;
			add_tilt_[2] += random_vec[2] * 0.01;
			
			if( add_tilt_[0] > 100)add_tilt_[0] = 100;
			if( add_tilt_[0] < -100)add_tilt_[0] = -100;
			
			if( add_tilt_[1] > 100)add_tilt_[1] = 100;
			if( add_tilt_[1] < -100)add_tilt_[1] = -100;
						
			if( add_tilt_[2] > 100)add_tilt_[2] = 100;
			if( add_tilt_[2] < -100)add_tilt_[2] = -100;
			
			//mat4.identity(view_matrix_);
			
			//view_matrix_[12] += 100.0;
			
			mat4.translate(view_matrix_, [add_tilt_[0], 0.0, 0.0]);
			mat4.translate(view_matrix_, [0.0, add_tilt_[1], 0.0]);
			mat4.translate(view_matrix_, [0.0, 0.0, add_tilt_[2]]);
			
			//mat4.rotateZ(view_matrix_, add_tilt_[0]);
			//mat4.rotateX(view_matrix_, init_rot[0]);
			//mat4.rotateY(view_matrix_, init_rot[1]);
			//mat4.rotateZ(view_matrix_, );
			//mat4.rotateX(view_matrix_, add_tilt_[1]);
			//mat4.rotateY(view_matrix_, add_tilt_[2]);
		};

		this.UpdatePlanes = function() {

			var combo_matrix = mat4.create();
			mat4.multiply(projection_matrix_, view_matrix_, combo_matrix);
			//combo_matrix = view_matrix_;
			//console.log(combo_matrix);

			planes_.left[0] = combo_matrix[4 * 0 + 3] + combo_matrix[4 * 0 + 0];
			planes_.left[1] = combo_matrix[4 * 1 + 3] + combo_matrix[4 * 1 + 0];
			planes_.left[2] = combo_matrix[4 * 2 + 3] + combo_matrix[4 * 2 + 0];
			planes_.left[3] = combo_matrix[4 * 3 + 3] + combo_matrix[4 * 3 + 0];

			planes_.right[0] = combo_matrix[4 * 0 + 3] - combo_matrix[4 * 0 + 0];
			planes_.right[1] = combo_matrix[4 * 1 + 3] - combo_matrix[4 * 1 + 0];
			planes_.right[2] = combo_matrix[4 * 2 + 3] - combo_matrix[4 * 2 + 0];
			planes_.right[3] = combo_matrix[4 * 3 + 3] - combo_matrix[4 * 3 + 0];

			planes_.top[0] = combo_matrix[4 * 0 + 3] - combo_matrix[4 * 0 + 1];
			planes_.top[1] = combo_matrix[4 * 1 + 3] - combo_matrix[4 * 1 + 1];
			planes_.top[2] = combo_matrix[4 * 2 + 3] - combo_matrix[4 * 2 + 1];
			planes_.top[3] = combo_matrix[4 * 3 + 3] - combo_matrix[4 * 3 + 1];

			planes_.bottom[0] = combo_matrix[4 * 0 + 3] + combo_matrix[4 * 0 + 1];
			planes_.bottom[1] = combo_matrix[4 * 1 + 3] + combo_matrix[4 * 1 + 1];
			planes_.bottom[2] = combo_matrix[4 * 2 + 3] + combo_matrix[4 * 2 + 1];
			planes_.bottom[3] = combo_matrix[4 * 3 + 3] + combo_matrix[4 * 3 + 1];

			planes_.near[0] = combo_matrix[4 * 0 + 3] + combo_matrix[4 * 0 + 2];
			planes_.near[1] = combo_matrix[4 * 1 + 3] + combo_matrix[4 * 1 + 2];
			planes_.near[2] = combo_matrix[4 * 2 + 3] + combo_matrix[4 * 2 + 2];
			planes_.near[3] = combo_matrix[4 * 3 + 3] + combo_matrix[4 * 3 + 2];

			planes_.far[0] = combo_matrix[4 * 0 + 3] - combo_matrix[4 * 0 + 2];
			planes_.far[1] = combo_matrix[4 * 1 + 3] - combo_matrix[4 * 1 + 2];
			planes_.far[2] = combo_matrix[4 * 2 + 3] - combo_matrix[4 * 2 + 2];
			planes_.far[3] = combo_matrix[4 * 3 + 3] - combo_matrix[4 * 3 + 2];

			var inv_l = 1 / Math.sqrt(planes_.left[0] * planes_.left[0] + planes_.left[1] * planes_.left[1] + planes_.left[2] * planes_.left[2]);
			planes_.left[0] *= inv_l;
			planes_.left[1] *= inv_l;
			planes_.left[2] *= inv_l;
			//alert(planes_.left[3]);
			planes_.left[3] *= inv_l;

			inv_l = 1 / Math.sqrt(planes_.right[0] * planes_.right[0] + planes_.right[1] * planes_.right[1] + planes_.right[2] * planes_.right[2]);
			planes_.right[0] *= inv_l;
			planes_.right[1] *= inv_l;
			planes_.right[2] *= inv_l;
			planes_.right[3] *= inv_l;

			inv_l = 1 / Math.sqrt(planes_.top[0] * planes_.top[0] + planes_.top[1] * planes_.top[1] + planes_.top[2] * planes_.top[2]);
			planes_.top[0] *= inv_l;
			planes_.top[1] *= inv_l;
			planes_.top[2] *= inv_l;
			planes_.top[3] *= inv_l;

			inv_l = 1 / Math.sqrt(planes_.bottom[0] * planes_.bottom[0] + planes_.bottom[1] * planes_.bottom[1] + planes_.bottom[2] * planes_.bottom[2]);
			planes_.bottom[0] *= inv_l;
			planes_.bottom[1] *= inv_l;
			planes_.bottom[2] *= inv_l;
			planes_.bottom[3] *= inv_l;

			inv_l = 1 / Math.sqrt(planes_.far[0] * planes_.far[0] + planes_.far[1] * planes_.far[1] + planes_.far[2] * planes_.far[2]);
			planes_.far[0] *= inv_l;
			planes_.far[1] *= inv_l;
			planes_.far[2] *= inv_l;
			planes_.far[3] *= inv_l;

			inv_l = 1 / Math.sqrt(planes_.near[0] * planes_.near[0] + planes_.near[1] * planes_.near[1] + planes_.near[2] * planes_.near[2]);
			planes_.near[0] *= inv_l;
			planes_.near[1] *= inv_l;
			planes_.near[2] *= inv_l;
			planes_.near[3] *= inv_l;

			//if(g_render_state.current_cam == main_cam)
			//alert(planes_.near);

		};

		this.IsInFrustum = function(box_points) {

			var total_in_count = 0,
				in_count,
				dot,
				plane;

			for (var prop in planes_) {

				plane = planes_[prop];

				in_count = 8;

				for (var i = 0; i < 8; i++) {
					
					dot = plane[0] * box_points[i][0] + plane[1] * box_points[i][1] + plane[2] * box_points[i][2];
					if (dot + plane[3] < 0)
					{
						in_count--;
					} else
					{
						total_in_count++;
					}

				}

				if (in_count == 0)
				{
					return false;
				}

			}

			return true;
			
		};
		
	};
	
	

	
	return Camera;

})();